<meta charset='utf8' />
<canvas id='canvas' width='420px' height='420px'></canvas>
<canvas id='canvas1' width='1024px' height='1024px'></canvas>
<script type='text/javascript' src='vector.js'></script>
<script type='text/javascript' src='color.js'></script>
<script type='text/javascript' src='ray.js'></script>
<script type='text/javascript' src='substance.js'></script>
<script type='text/javascript' src='perspectiveCamera.js'></script>
<script type='text/javascript' src='material.js'></script>
<script type='text/javascript' src='light.js'></script>
<script type='text/javascript' src='union.js'></script>
<script type='text/javascript'>
	var ctx = canvas.getContext('2d');
	
	function test(scene, camera, maxDepth) {
		var w = canvas.width;
		var h = canvas.height;
		ctx.fillRect(0, 0, w, h);
		
		scene.initialize();
		camera.initialize();

		var imgData = ctx.getImageData(0, 0, w, h);
		var pixels = imgData.data;
		var sx, sy;
		var ray, result, color;
		var i = 0;
		for(var y = 0; y < h; y++) {
			sy = 2 * y / h - 1;
			for(var x = 0; x < w; x++) {
				sx = 2 * x / w - 1;
				ray = camera.generateRay(sx, sy);

				var color = rayReflex(scene, ray, 1, 1);
				pixels[i] = color.r * 255;
				pixels[i + 1] = color.g * 255;
				pixels[i + 2] = color.b * 255;
				pixels[i + 3] = 255;
				i += 4;
			}
		}
		ctx.putImageData(imgData, 0, 0);
	}
	function rayReflex(scene, ray, prindex, maxDepth) {
		var c = Color.black;
		if(maxDepth <= 0) {
			return c;
		}
		var result = scene.intersect(ray);
		if(!result.geometry) {
			var light, result;
			for(var i = 0; i < lights.length; i++) {
				light = lights[i]
				result = light.intersect(ray);
				if(result.geometry) {
					return new Color(1, 1, 1);
				}
			}
			return c;
		}
		var shade, light;
		var color = result.geometry.material.sample(ray, result.position, result.normal, result.geometry);
		for(var i = 0; i < lights.length; i++) {
			light = lights[i]
			shade = light.shade(scene, result.position);
			light.intersect(ray);
			var diffuse = result.geometry.material.diffuse;
			var L = light.l.subtract(result.position).normalize();
			var NdotL = result.normal.dot(L);
			var diffuseTemp = color.multiply(Math.max(NdotL * shade * diffuse, 0));
			c = c.add(light.el.modulate(diffuseTemp));
			
			var specular = result.geometry.material.specular;
			var R =  L.subtract(result.normal.multiply(2 * NdotL));
			var NdotR = ray.direction.dot(R);
			if(NdotR > 0) {
				var secularTemp = Math.pow(NdotR, 20) * specular * shade;
				c = c.add(light.el.multiply(secularTemp));
			}
		}

		var reflect = result.geometry.material.reflect;
		if(reflect > 0) {
			var r = result.normal.multiply(-2 * result.normal.dot(ray.direction)).add(ray.direction);
			var flexRay = new Ray3(result.position, r);
			var reflectedColor = rayReflex(scene, flexRay, prindex, maxDepth - 1);
			c = c.add(reflectedColor.multiply(reflect).modulate(color));
		}

		var refract = result.geometry.material.refract;
		if(reflect > 0) {
			var rindex = result.geometry.material.rindex;
			if(rindex <= 0) {
				return c;
			}
			if(result.dir == -1) {
				rindex = 1;
			}
			var n = prindex / rindex;
			var cosI = -(result.normal.dot(ray.direction));
			var cosT2 =1 - Math.pow(n, 2) *(1 - Math.pow(cosI, 2));
			if (cosT2 > 0) {
				var cosT = Math.sqrt(cosT2);
				var T = ray.direction.multiply(n).add(result.normal.multiply(n * cosI - cosT));
				var fractRay = new Ray3(result.position, T);
				var rcol = rayReflex(scene, fractRay, rindex, maxDepth - 1);
				c = c.add(rcol.multiply(refract));
			}
		}

		return c;
	}
	
	var areaLight = new AreaLight(new Color(1, 1, 1), new Vector3(0.3 , 1.2 , 0.8), new Vector3(0.6 , 1.2 , 0.8), new Vector3(0.6 , 1.5 , 0.8), new Vector3(0.3 , 1.5 , 0.8));

	var l1 = new LightSample(new Vector3(5 , -5 , -2), new Color(1,1,1));
	var l2 = new LightSample(new Vector3(-5 , 5 , 1), new Color(0.3 , 0.3 , 0.3));
	var l3 = new LightSample(new Vector3(5 , -5 , 1), new Color(0.3 , 0.3 , 0.3));
	var l4 = new LightSample(new Vector3(5 , 5 , 1), new Color(0.3 , 0.3 , 0.3));
	var l5 = new LightSample(new Vector3(-5 , 0 , 1), new Color(0.3 , 0.3 , 0.3));
	var l6 = new LightSample(new Vector3(0 , 5 , 1), new Color(0.3 , 0.3 , 0.3));
	var l7 = new LightSample(new Vector3(5 , 0 , 1), new Color(0.3 , 0.3 , 0.3));
	var l8 = new LightSample(new Vector3(0 , 5 , 1), new Color(0.3 , 0.3 , 0.3));
	var lights = [l1];

	var s1 = new Sphere(new Vector3(0, -0.5, 0), 0.5);
	s1.material = new PhoneMaterial(1, 0.1, 0.3, 0.7, Color.white, 1.05);

	var s2 = new Sphere(new Vector3(0, 1, 0.2), 0.2);
	s2.material = new PhoneMaterial(0.2, 0.05, 0.75, 0, new Color(0, 1, 1));

	var s3 = new Sphere(new Vector3(0.4, 1.7 , 0.2), 0.2);
	s3.material = new PhoneMaterial(0.2, 0.05, 0.75, 0, new Color( 1, 0, 1));

	var plane = new Plane(new Vector3(0, -1, 0), 0);
	plane.material = new CheckerMaterial(0.2, 0.2, 0.6, 0, 10 / 3);

	var camera = new Camera(new Vector3(0, -1.2, 0), new Vector3(0, 1, 0), new Vector3(-1, 0, 0), 90);
	var start = new Date().getTime();
	//test(new Union([plane, s1]), camera, 60);
	var end = new Date().getTime();

	var img = new Image();
	var imgPixels;
	var imgPixels2;
	img.onload = function(){
		ctx.drawImage(img, 0, 0);
		imgPixels = ctx.getImageData(0, 0, 420, 420).data;
		img = new Image();
		img.onload = function(){
			canvas1.getContext('2d').drawImage(img, 0, 0);
			var ii = canvas1.getContext('2d').getImageData(0, 0, 1024, 1024);
			imgPixels2 = ii.data;
			test(new Union([plane, s1]), camera, 60);
			canvas1.getContext('2d').putImageData(ii, 0, 0);
		}
		img.src = 'sphere_texture.bmp';
	}
	img.src = 'floor_board.bmp';
</script>